﻿
namespace CoProjectDF.Views.Login
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using CoProjectDF.Models.Login;
    using CoProjectModel;
    using IdeaBlade.Application.Framework.Core.Authentication;
    using IdeaBlade.Application.Framework.Core.Persistence;
    using IdeaBlade.EntityModel;

    public class RegisterUserRepository
    {
        public RegisterUserRepository()
        {
            AuthenticationService = Caliburn.Micro.IoC.Get<IAuthenticationService>();
            EntityManagerProvider = Caliburn.Micro.IoC.Get<IEntityManagerProvider<CoProjectModel.CoProjectEntities>>();
        }

        #region New User Registration

        /// <summary>
        /// Register a new user.
        /// </summary>
        /// <param name="user"></param>
        /// <param name="loginRegisteredUser"></param>
        /// <param name="callback"></param>
        /// <returns></returns>

        public BaseOperation RegisterUser(RegistrationData user, bool loginRegisteredUser = true, Action<BaseOperation> callback = null)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }

            var op = Coroutine.Start(() => RegisterUserCore(user, user.Password, loginRegisteredUser));
            op.Completed += (s, e) =>
            {
                if (op.CompletedSuccessfully)
                {
                    OnPropertyChanged("User");
                    OnLoggedIn();
                }
                if (callback != null)
                {
                    callback(op);
                }
            };
            return op;
        }

        /// <summary>
        /// An iterator block to perform user registration.
        /// </summary>
        private IEnumerable<INotifyCompleted> RegisterUserCore(RegistrationData user, string password, bool loginRegisteredUser)
        {
            // Call a server-side method.  Note type name must be fully-qualifed:  MyNamespace.MyClass, MyAssemblyName
            string typeName = "CoProjectDF.RegistrationServices, CoProjectDF.Web";
            string methodName = "CreateUser";
            var op1 = Manager.InvokeServerMethodAsync(typeName, methodName, null, null, user, password);
            yield return op1;

            CreateUserResult result = op1.Result as CreateUserResult;
            if (result.Status != CreateUserStatus.Success)
            {
                // Throw an exception here - the caller can decide what to do.  
                throw new RegistrationException(result);
            }

            // We'll get here if the above succeeded and the new user has been registered.  Login if wanted.
            if (loginRegisteredUser)
            {
                // DevForce will not perform a login if the EM is already logged in, so logout before supplying new credentials.
                var op2 = Manager.LogoutAsync();
                yield return op2;

                var op3 = Manager.LoginAsync(user.ToLoginCredential());
                yield return op3;
            }
        }

        #endregion

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected virtual void OnLoggedIn()
        {
            if (LoggedIn != null)
            {
                LoggedIn(this, EventArgs.Empty);
            }
        }

        protected virtual void OnLoggedOut()
        {
            if (LoggedOut != null)
            {
                LoggedOut(this, EventArgs.Empty);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public event EventHandler LoggedIn;
        public event EventHandler LoggedOut;

        /// <summary>
        /// Gets or Sets the AuthenticationService from the IoC container.
        /// </summary>
        private IAuthenticationService AuthenticationService { get; set; }
        private IEntityManagerProvider<CoProjectModel.CoProjectEntities> EntityManagerProvider { get; set; }
        private CoProjectEntities Manager { get { return EntityManagerProvider.Manager; } }
    }
}
